<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
    let target = null
    function Vue({data}){
        this._data = data
    //    数据代理
        for (let key in this._data){
            Object.defineProperty(this,key,{
                get:function proxyGetter(){
                    return this._data[key]
                },
                set:function proxySetter(newVal){
                    this._data[key] = newVal
                }
            })
        }

    //    数据劫持
        observe(this._data)
    }

    function observe(data){
        if(typeof data !== 'object' || data === null)return
    //    数据劫持
        new Observer(data)
    }

    //发布者+数据劫持
    class Observer{
        constructor(data) {
            this.data = data
            if(Array.isArray(this.data)){
                this.observerArr(this.data)
            }else {
                this.walk(this.data)
            }
        }

    //    数组劫持
        observerArr(data){
            data.forEach(item=>{
                observe(item)
            })
        }
    //    劫持对象
        walk(data){
            for (let key in data){
                defineReactive(data,key)
            }
        }
    }

    //数据劫持的核心
    function defineReactive(data,key){
        let value = data[key]
        //数据劫持之前创建订阅中心
        let dep = new Dep()
        //深度监听对象
        observe(value)
        Object.defineProperty(data,key,{
            get:function reactiveGetter(){
                if(target){
                    dep.depend(target)
                }
                return value
            },
            set:function reactiveSetter(newVal){
                if(newVal===value)return
                value = newVal
            //    发布通知watcher进行视图更新
                dep.notify()
            }
        })
    }

    //创建订阅中心
    class Dep{
        constructor() {
            this.sub = []
        }
    //    收集依赖
        depend(watcher){
            this.sub.push(watcher)
        }
    //    发布通知
        notify(){
            this.sub.forEach(item=>{
                item.update()
            })
        }
    }

    //创建订阅者，当模板中获取数据时就订阅一次
    class Watcher{
        constructor(data,key) {
            this.data = data
            this.key = key
            target = this
            this.get()
            target = null
        }

    //    获取最新数据
        get(){
            return this.data[this.key]
        }

    //    更新视图
        update(){
            console.log('视图已更新')
        }
    }
    const vm = new Vue({
        data:{
            count:12,
            arr:['kobe',{name:'zhangSan',age:18},{name:'lisi',age:17}]
        }
    })
    console.log(vm)
    new Watcher(vm,'count')
    new Watcher(vm.arr[1],'age')
</script>
</body>
</html>